/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.admin.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xxl.job.core.util.IpUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.mq.RescueDelaySend;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tenant.mp.TenantEntity;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.modules.admin.dto.RescueNoticeCreateDTO;
import org.springblade.modules.admin.dto.RescueRoomPersonDTO;
import org.springblade.modules.admin.dto.rescue.*;
import org.springblade.modules.admin.entity.*;
import org.springblade.modules.admin.enums.*;
import org.springblade.modules.admin.event.RescueTrappedNoticeEvent;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.utils.AsyncUtils;
import org.springblade.modules.admin.utils.DateUtils;
import org.springblade.modules.admin.vo.CurRescueNoticeVO;
import org.springblade.modules.admin.vo.RescueNoticeStatisticsVO;
import org.springblade.modules.admin.vo.RescueNoticeVO;
import org.springblade.modules.admin.mapper.RescueNoticeMapper;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.modules.admin.vo.SimpleElevatorInfoVO;
import org.springblade.modules.admin.vo.rescue.*;
import org.springblade.modules.system.entity.TenantConfig;
import org.springblade.modules.system.enums.DayType;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.service.TenantConfigService;
import org.springblade.modules.system.vo.config.AlarmConfig;
import org.springblade.modules.system.vo.config.TimePeriodValidator;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 救援通知记录表 服务实现类
 *
 * @author ysq
 * @since 2023-09-14
 */
@Slf4j
@AllArgsConstructor
@Service
public class RescueNoticeServiceImpl extends BaseServiceImpl<RescueNoticeMapper, RescueNotice> implements IRescueNoticeService {

	private final IUserService userService;
	private final ElevatorDeviceService elevatorDeviceService;
	private final IRescueNoticeSessionService rescueNoticeSessionService;
	private final AsyncUtils asyncUtils;
	private final BladeRedis bladeRedis;
	private final ElevatorPrincipalDeptService elevatorPrincipalDeptService;
	private final IBuildingContactsService buildingContactsService;
	private final IRescueNoticeAiSessionService aiNoticeSessionService;
	private final IRescueNoticeAiSessionContentService aiNoticeSessionContentService;
	private final ElevatorService elevatorService;
	private final TenantConfigService tenantConfigService;
	private final ApplicationEventPublisher applicationEventPublisher;
	private final Environment environment;
	private final RescueDelaySend rescueDelaySend;
	private final BuildingService buildingService;
	private final IRescueNoticeAiSessionService noticeAiSessionService;
	private final IElevatorDetailService elevatorDetailService;
	private final IRescueNoticeAiSessionContentService noticeAiContentService;

	@Override
	public IPage<RescueNoticeVO> selectRescueNoticePage(IPage<RescueNoticeVO> page, RescueNoticeVO rescueNotice) {
		List<RescueNoticeVO> list = baseMapper.selectRescueNoticePage(page, rescueNotice);
		return page.setRecords(dataHandler(list));
	}

	/**
	 * 数据处理
	 * @param list
	 */
	private List<RescueNoticeVO> dataHandler(List<RescueNoticeVO> list) {
		for (RescueNoticeVO item : list) {
			item.setResponseTimeFormat(DateUtils.chineseBetweenTime(item.getCallTime(), item.getSessionStartTime()));
			item.setSessionTimeFormat(DateUtils.chineseBetweenTime(item.getSessionStartTime(), item.getSessionEndTime()));
			item.setRescueTimeFormat(DateUtils.chineseBetweenTime(item.getCreateTime(), item.getPlanEndTime()));
		}
		return list;
	}

	@Override
	public RescueNoticeStatisticsVO statistics() {
		RescueNoticeStatisticsVO statistics = new RescueNoticeStatisticsVO();
		List<RescueNoticeVO> list = dataHandler(baseMapper.selectRescueNoticePage(null, new RescueNoticeVO()));
		statistics.setCallTotal(list.stream().count());

		// 总响应次数
		long responseTotal = list.stream().filter(t -> t.getResponseTimeFormat() != null).count();
		// 总响应时长（秒）
		long responseTimeTotal = list.stream().filter(t -> t.getResponseTimeFormat() != null).collect(Collectors.summingLong(t -> DateUtil.between(t.getCallTime(), t.getSessionStartTime(), DateUnit.SECOND)));
		if (responseTotal > 0) {
			// 平均响应时间：累计紧急呼叫次数响应时间相加 \ 总响应次数 =平均响应时间 （秒）精确到小数点后一位
			BigDecimal responseAvg = new BigDecimal(responseTimeTotal).divide(new BigDecimal(responseTotal),1, BigDecimal.ROUND_HALF_UP);
			statistics.setResponseAvg(responseAvg);
		}

		// 总会话次数
		long sessionTotal = list.stream().filter(t -> t.getSessionTimeFormat() != null).count();
		// 总会话时长（秒）
		long sessionTimeTotal = list.stream().filter(t -> t.getSessionTimeFormat() != null).collect(Collectors.summingLong(t -> DateUtil.between(t.getSessionStartTime(), t.getSessionEndTime(), DateUnit.SECOND)));
		if (sessionTotal > 0) {
			// 平均会话时长：累计紧急呼叫次数会话时长时间相加 \ 总会话次数 = 平均会话时长
			long sessionMin = sessionTimeTotal / sessionTotal;
			long sessionSecond =  sessionTimeTotal / sessionTotal % 60;
			String sessionTimeAvg = sessionMin > 60 ? (sessionMin / 60 + "分" + sessionSecond + "秒") : (sessionSecond + "秒");
			statistics.setSessionTimeAvg(sessionTimeAvg);
		}

		// 总救援次数
		long rescueTotal = list.stream().filter(t -> t.getRescueTimeFormat() != null).count();
		// 总救援时长（秒）
		long rescueTimeTotal = list.stream().filter(t -> t.getRescueTimeFormat() != null).collect(Collectors.summingLong(t -> DateUtil.between(t.getCreateTime(), t.getPlanEndTime(), DateUnit.SECOND)));
		if (rescueTotal > 0) {
			// 平均救援用时（一键呼救）：累计紧急呼叫次数救援用时时间相加（已救援） \ 累计紧急呼叫次数（已救援）  = 平均救援用时
			long rescueMin = rescueTimeTotal / rescueTotal;
			long rescueSecond =  rescueTimeTotal / rescueTotal % 60;
			String rescueTimeAvg = rescueMin > 60 ? (rescueMin / 60 + "分" + rescueSecond + "秒") : (rescueSecond + "秒");
			statistics.setRescueTimeAvg(rescueTimeAvg);
		}

		return statistics;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Long rescueNoticeSave(RescueNoticeCreateDTO rescueNoticeCreate) throws ServiceException {
		log.warn("接收到请求参数：{}", rescueNoticeCreate);
		SimpleElevatorInfoVO simpleElevatorInfoVO = elevatorDeviceService.getSimpleElevatorInfo(rescueNoticeCreate.getDeviceId());
		if (Func.isEmpty(simpleElevatorInfoVO)) {
			throw new ServiceException("电梯不存在");
		}

		// 根据电梯租户id，查询租户配置
		Long elevatorId = simpleElevatorInfoVO.getElevatorId();
		Elevator currentElevator = elevatorService.getById(elevatorId);
		TenantConfig tenantConfig = tenantConfigService.getTenantConfig(currentElevator.getTenantId());
		// 获取告警配置
		AlarmConfig alarmConfig = tenantConfig.getAlarmConfig();
		AlarmConfig.TlwAlarm tlwAlarm = alarmConfig.getTlwAlarm();
		// 获取当前时间
		String format = DateUtil.format(new Date(), "HH:mm");
		log.info(tlwAlarm.isEnabled() + " " + tlwAlarm.getPeriods() + " " + format);
		log.info(" " + TimePeriodValidator.isTimeInPeriods(DayType.当日, format, tlwAlarm.getPeriods()));
		if(!(tlwAlarm.isEnabled() && TimePeriodValidator.isTimeInPeriods(DayType.当日, format, tlwAlarm.getPeriods()))){
			return null;
		}
		// 重复校验
		StringBuilder key = new StringBuilder("RESCUE_CREATE:").append(rescueNoticeCreate.getRescueId()).append(StringPool.COLON)
			.append(rescueNoticeCreate.getDeviceId());
		if (bladeRedis.exists(key.toString())) {
			return null;
		}
		// 2025-07 告警信息取消工单必填, 存储救援通知，新增救援通知新字段
		RescueNotice rescueNotice = new RescueNotice();
		rescueNotice.setDeviceId(rescueNoticeCreate.getDeviceId());
		rescueNotice.setCallId(rescueNoticeCreate.getRescueId());
		rescueNotice.setBizPrefix("HJ" + DateUtil.format(new Date(), "yyyyMMdd"));
		rescueNotice.setCallTime(DateUtil.date(rescueNoticeCreate.getRescueTimeStamp()));
		rescueNotice.setFloorNumber(rescueNoticeCreate.getFloorNumber());
		rescueNotice.setEventCode(rescueNoticeCreate.getEventCode());
		rescueNotice.setEventName(rescueNoticeCreate.getEventName());
		rescueNotice.setEventLevel(rescueNoticeCreate.getEventLevel());

		rescueNotice.setElevatorId(simpleElevatorInfoVO.getElevatorId());
		rescueNotice.setBuildingId(simpleElevatorInfoVO.getBuildingId());
		rescueNotice.setBuildingName(simpleElevatorInfoVO.getBuildingName());
		rescueNotice.setElevatorAddress(simpleElevatorInfoVO.getElevatorAddress());
		rescueNotice.setTenantId(simpleElevatorInfoVO.getTenantId());
		rescueNotice.setElevatorStop(simpleElevatorInfoVO.getIsStop());

		boolean isSaveSuccess = this.save(rescueNotice);
		if (isSaveSuccess) {
			// 发送延迟队列
			// 延迟时间从超时配置中获取
			int confirmTimeOut = tenantConfig.getConfig().containsKey("notConfirm")
				? (int) Double.parseDouble(String.valueOf(tenantConfig.getConfig().get("notConfirm")))
				: 2;
			long timeout = confirmTimeOut * 60L;
			String curEnvironment = environment.getActiveProfiles()[0];
			JSONObject delayMsg = new JSONObject();
			delayMsg.put("type", 2);
			delayMsg.put("taskId", rescueNotice.getId());
			delayMsg.put("environment", curEnvironment);
			long sendTime =  DateUtil.date().getTime() + timeout * 1000;
			rescueDelaySend.sendDelayMsg(sendTime, delayMsg.toJSONString());

			log.info("紧急呼叫-创建救援告警成功，ip: {}", IpUtil.getIp());
			bladeRedis.setEx(key.toString(), 1, 5L);
			// 发送告警通知
			this.sendAlarmNotice(alarmConfig.getAlarmDeduplication(), rescueNotice.getId(), simpleElevatorInfoVO.getTenantId(),
				elevatorId, rescueNoticeCreate.getEventCode());
		}
		return rescueNotice.getId();
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Long createRescueNoticeFromGroup(GroupAINoticeCreateDTO groupAINoticeCreateDTO) {
		String tenantId = null;
		// 根据群组id获取项目id
		Long buildingId = null;
		Long elevatorId = 0L;
		String groupId = groupAINoticeCreateDTO.getGroupId();
		List<Long> buildingIds = buildingService.getBuildingIdsByGroupId(groupId);
		if(Func.isNotEmpty(buildingIds)){
			buildingId = buildingIds.get(0);
		}
		Building currentBuilding = buildingService.getById(buildingId);
		if(Func.isEmpty(currentBuilding)){
			throw new ServiceException("预警创建失败，未找到对应的项目");
		}
		tenantId = currentBuilding.getTenantId();
		if(Func.isEmpty(tenantId)){
			throw new ServiceException("预警创建失败，未找到对应的租户");
		}
		String buildingName = currentBuilding.getName();
		// 根据坤哥传参，获取电梯id
		String elevatorAddress = groupAINoticeCreateDTO.getElevatorAddress();
		if(Func.isNotBlank(elevatorAddress)){
			List<ElevatorDetail> elevatorDetailList = elevatorDetailService.list(new LambdaQueryWrapper<ElevatorDetail>()
				.eq(ElevatorDetail::getElevatorAddress, elevatorAddress)
				.eq(TenantEntity::getTenantId, tenantId)
				.eq(BaseEntity::getIsDeleted, 0)
			);
			if(Func.isNotEmpty(elevatorDetailList) && elevatorDetailList.size() == 1){
				elevatorId = elevatorDetailList.get(0).getElevatorId();
			}
		}
		// 1. 创建告警记录
		RescueNotice rescueNotice = new RescueNotice();
		rescueNotice.setBuildingId(buildingId);
		rescueNotice.setBuildingName(buildingName);
		rescueNotice.setElevatorId(elevatorId);
		rescueNotice.setTenantId(tenantId);
		rescueNotice.setEventCode(RescueNoticeTypeEnum.CHAT_GROUP_AI.getEventCode());
		boolean rescueNoticeSave = this.save(rescueNotice);
		// 2. 当告警记录创建成功，将告警记录id赋值到会话
		if(rescueNoticeSave){
			String member = groupAINoticeCreateDTO.getMember();
			RescueNoticeAiSession rescueNoticeAiSession = new RescueNoticeAiSession();
			rescueNoticeAiSession.setTenantId(tenantId);
			rescueNoticeAiSession.setNoticeId(rescueNotice.getId());
			rescueNoticeAiSession.setGroupId(groupId);
			rescueNoticeAiSession.setGroupName(groupAINoticeCreateDTO.getGroupName());
			rescueNoticeAiSession.setMember(member);
			LocalDateTime chatBeginTime = groupAINoticeCreateDTO.getChatBeginTime();
			LocalDateTime chatEndTime = groupAINoticeCreateDTO.getChatEndTime();
			rescueNoticeAiSession.setChatBeginTime(chatBeginTime);
			rescueNoticeAiSession.setChatEndTime(chatEndTime);
			if(Func.isNotEmpty(chatBeginTime) && Func.isNotEmpty(chatEndTime)){
				// 根据开始时间、结束时间，计算会话时长，单位秒
				// 先将时间转换为Date
				Date chatBeginDate = DateUtil.date(chatBeginTime);
				Date chatEndDate = DateUtil.date(chatEndTime);
				long chatTime = DateUtil.between(chatBeginDate, chatEndDate, DateUnit.SECOND);
				rescueNoticeAiSession.setChatTime(chatTime);
			}
			rescueNoticeAiSession.setChatTime(groupAINoticeCreateDTO.getChatTime());
			rescueNoticeAiSession.setContactPhone(groupAINoticeCreateDTO.getContactPhone());
			rescueNoticeAiSession.setMemberCount(2);
			rescueNoticeAiSession.setConvertType(-1);
			rescueNoticeAiSession.setIsConvert(0);
			rescueNoticeAiSession.setReportName("困人报警");
			rescueNoticeAiSession.setReportSource(groupAINoticeCreateDTO.getReportSource());
			boolean isSaveSession = noticeAiSessionService.save(rescueNoticeAiSession);
			// 3. 当会话存储成功，将DTO中的对象赋值到会话内容
			if(isSaveSession){
				List<RescueNoticeAiSessionContent> batchResult = new ArrayList<>();
				List<AiSessionContentDTO> contentDTOS = groupAINoticeCreateDTO.getContentDTOS();
				String finalTenantId = tenantId;
				Long finalSessionId = rescueNoticeAiSession.getId();
				contentDTOS.forEach(c -> {
					String messageType = c.getMessageType();
					if(Func.isNotEmpty(messageType)){
						if("USER".equals(messageType)){
							c.setMember(member);
							c.setMemberType(1);
						}else{
							c.setMember("微信群客服AI");
							c.setMemberType(2);
						}
					}
					c.setAiSessionId(finalSessionId);

					RescueNoticeAiSessionContent saveResult = new RescueNoticeAiSessionContent();
					saveResult.setMemberType(c.getMemberType());
					saveResult.setAiSessionId(c.getAiSessionId());
					saveResult.setMember(c.getMember());
					saveResult.setTenantId(finalTenantId);
					saveResult.setContent(c.getContent());
					LocalDateTime createTime = c.getCreateTime();
					if(Func.isNotEmpty(createTime)){
						Date insertDate = DateUtil.date(createTime);
						saveResult.setCreateTime(insertDate);
					}
					batchResult.add(saveResult);
				});
				noticeAiContentService.saveBatch(batchResult);
			}
		}
		// 发送延迟队列
		TenantConfig tenantConfig = tenantConfigService.getTenantConfig(tenantId);
		int confirmTimeOut = tenantConfig.getConfig().containsKey("notConfirm")
			? (int) Double.parseDouble(String.valueOf(tenantConfig.getConfig().get("notConfirm")))
			: 2;
		long timeout = confirmTimeOut * 60L;
		String curEnvironment = environment.getActiveProfiles()[0];
		JSONObject delayMsg = new JSONObject();
		delayMsg.put("type", 2);
		delayMsg.put("taskId", rescueNotice.getId());
		delayMsg.put("environment", curEnvironment);
		long sendTime =  DateUtil.date().getTime() + timeout * 1000;
		rescueDelaySend.sendDelayMsg(sendTime, delayMsg.toJSONString());

		// 发送告警通知
		this.sendAlarmNotice(tenantConfig.getAlarmConfig().getAlarmDeduplication(), rescueNotice.getId(), tenantId,
			elevatorId, rescueNotice.getEventCode());

		return rescueNotice.getId();
	}

	/**
	 * 发送报警通知
	 * @param alarmDeduplication 报警通知配置
	 * @param rescueId 救援记录id
	 * @param tenantId 租户id
	 * @param elevatorId 电梯id
	 * @param eventCode 报警事件代码
	 */
	private void sendAlarmNotice(AlarmConfig.AlarmDeduplicationNotice alarmDeduplication, Long rescueId, String tenantId, Long elevatorId, String eventCode) {
		if (elevatorId == 0L) {
			return;
		}

		/**
		 * 报警通知说明：
		 * 1."一键救援"事件都拨打电话通知
		 * 2.其它事件基于通知开关和时间窗口拨打电话通知
		 */
		boolean isSendAlarmNotice = true;
		// 构建Redis缓存key
		String rescueNoticeKey = NOTICE_KEY.concat(StringPool.DASH).concat(String.valueOf(elevatorId));

		// 检查是否为"一键救援"事件
		boolean isOneTouchRescue = Func.equalsSafe(RescueNoticeTypeEnum.ONE_TOUCH.getEventCode(), eventCode);
		// 非"一键救援"事件且启用重复报警去重时，检查是否已存在
		if (!isOneTouchRescue && alarmDeduplication.isEnabled()) {
			try {
				if (bladeRedis.exists(rescueNoticeKey)) {
					isSendAlarmNotice = false;
					log.info("检测到重复报警，电梯ID: {}，事件代码: {}，跳过通知", elevatorId, eventCode);
				}
			} catch (Exception e) {
				log.error("检查重复报警缓存失败，电梯ID: {}，事件代码: {}，错误: {}", elevatorId, eventCode, e.getMessage(), e);
				// Redis异常时，为了安全起见，仍然发送通知
				isSendAlarmNotice = true;
			}
		}

		// 设置Redis缓存，用于后续重复报警检测
		try {
			long expireSeconds = alarmDeduplication.getTimeWindowMinutes() * 60L;
			bladeRedis.setEx(rescueNoticeKey, 1, expireSeconds);
			log.debug("设置重复报警缓存，key: {}，过期时间: {}秒", rescueNoticeKey, expireSeconds);
		} catch (Exception e) {
			log.error("设置重复报警缓存失败，key: {}，错误: {}", rescueNoticeKey, e.getMessage(), e);
		}

		// 发送通知
		if (isSendAlarmNotice) {
			try {
				RescueTrappedNoticeDTO noticeParam = new RescueTrappedNoticeDTO();
				noticeParam.setRescueNoticeId(rescueId);
				noticeParam.setTenantId(tenantId);
				applicationEventPublisher.publishEvent(new RescueTrappedNoticeEvent(noticeParam));
				log.info("发布救援通知事件成功，救援通知ID: {}，电梯ID: {}", rescueId, elevatorId);
			} catch (Exception e) {
				log.error("发布救援通知事件失败，救援通知ID: {}，电梯ID: {}，错误: {}", rescueId, elevatorId, e.getMessage(), e);
			}
		}
	}

	@Override
	public void rescueNoticeSessionSave(RescueRoomPersonDTO rescueRoomPerson) {
		if (rescueRoomPerson.getDeviceType().equals(VideoDeviceTypeEnum.DEVICE.getType())) {
			return;
		}
		RescueNotice rescueNotice = baseMapper.getCurRescueNotice(Long.valueOf(rescueRoomPerson.getElevatorId()));
		if (Func.isEmpty(rescueNotice)) {
			return;
		}

		if ("room_login".equals(rescueRoomPerson.getEvent())) {
			// 重复校验
			StringBuilder key = new StringBuilder("ROOM_LOGIN:").append(rescueRoomPerson.getDeviceType()).append(StringPool.COLON)
				.append(rescueNotice.getId()).append(StringPool.COLON).append(rescueRoomPerson.getUserId());
			if (bladeRedis.exists(key.toString())) {
				return;
			}

			// 加入会话
			RescueNoticeSession rescueNoticeSession = new RescueNoticeSession();
			rescueNoticeSession.setRescueNoticeId(rescueNotice.getId());
			rescueNoticeSession.setCallId(rescueNotice.getCallId());
			rescueNoticeSession.setRoomId(rescueRoomPerson.getRoomId());
			rescueNoticeSession.setElevatorId(rescueNotice.getElevatorId());
			rescueNoticeSession.setDeviceId(rescueNotice.getDeviceId());
			rescueNoticeSession.setUserId(rescueRoomPerson.getUserId());
			rescueNoticeSession.setUserName(rescueRoomPerson.getServiceName());
			rescueNoticeSession.setDeviceType(rescueRoomPerson.getDeviceType());
			rescueNoticeSession.setSessionStartTime(DateUtil.date(rescueRoomPerson.getLoginTime()));
			if (rescueNoticeSessionService.save(rescueNoticeSession)) {
				bladeRedis.setEx(key.toString(), 1, 5L);
			}
		} else {
			// 退出会话
			RescueNoticeSession rescueNoticeSession = rescueNoticeSessionService.getOne(Wrappers.<RescueNoticeSession>lambdaQuery()
				.eq(RescueNoticeSession :: getRescueNoticeId, rescueNotice.getId())
				.eq(RescueNoticeSession :: getRoomId, rescueRoomPerson.getRoomId())
				.eq(RescueNoticeSession :: getDeviceType, rescueRoomPerson.getDeviceType())
				.isNull(RescueNoticeSession :: getSessionEndTime), false);
			if (Func.isEmpty(rescueNoticeSession)) {
				return;
			}
			rescueNoticeSession.setSessionEndTime(DateUtil.date(rescueRoomPerson.getLogoutTime()));
			rescueNoticeSessionService.updateById(rescueNoticeSession);
		}
	}

	@Override
	public List<CurRescueNoticeVO> curRescueNoticeList(String tenantId) {
		List<CurRescueNoticeVO> curRescueNoticeList = baseMapper.curRescueNoticeList(tenantId);
		for (CurRescueNoticeVO notice : curRescueNoticeList) {
			// 会话中列表
			List<RescueNoticeSession> sessionList = rescueNoticeSessionService.list(Wrappers.<RescueNoticeSession>lambdaQuery()
				.eq(RescueNoticeSession :: getRescueNoticeId, notice.getId())
				.isNull(RescueNoticeSession :: getSessionEndTime));

			// 通话中统计数据
			Map<String, Long> callTypeStatistics = sessionList.stream().collect(Collectors.groupingBy(t -> t.getDeviceType(), Collectors.counting()));
			notice.setCallTypeStatistics(callTypeStatistics);

			// 通话中详情人员
			Map<String, List<RescueNoticeSession>> callSessions = sessionList.stream().collect(Collectors.groupingBy(t -> t.getDeviceType()));
			notice.setCallSessions(callSessions);
		}

		return curRescueNoticeList;
	}

	@Override
	public IPage<RescueNoticeListVO> getNoticeListByCondition(IPage<RescueNoticeListVO> page,RescueNoticeListDTO rescueNoticeListDTO) {
		IPage<RescueNoticeListVO> noticeListByCondition = baseMapper.getNoticeListByCondition(page, rescueNoticeListDTO);
		// 数据描述处理
		List<RescueNoticeListVO> records = noticeListByCondition.getRecords();
		records.forEach(r -> {
			String eventCode = r.getEventCode();
			if(Func.isNotEmpty(eventCode)){
				r.setEventCodeDesc(RescueNoticeTypeEnum.getSourceByEventCode(eventCode));
			}
			Integer eventLevel = r.getEventLevel();
			if(Func.isNotEmpty(eventLevel)){
				r.setEventLevelDesc(RescueNoticeEventLevelEnum.getEventLevelDescByEventLevel(eventLevel));
			}
			// 工单类型及状态
			Integer typeStatus = r.getTypeStatus();
			if(Func.isNotEmpty(typeStatus)){
				r.setTypeStatusDesc(MaintainPlanContentEnum.getName(typeStatus));
				Integer status = r.getStatus();
				r.setStatusDesc(TaskStatusEnum.getTaskName(typeStatus, status));
			}
			Integer confirmType = r.getConfirmType();
			if(Func.isNotEmpty(confirmType)){
				r.setConfirmTypeDesc(RescueNoticeConfirmTypeEnum.getConfirmTypeDescByConfirmType(confirmType));
			}
		});
		noticeListByCondition.setRecords(records);
		return noticeListByCondition;
	}

	@Override
	public RescueNoticeDetailVO getNoticeDetailById(Long rescueNoticeId) {
		// 1. 根据告警id查询告警详情
		RescueNoticeDetailVO rescueNoticeDetailVO = baseMapper.getNoticeDetailById(rescueNoticeId);
		// 2. 补充告警详情
		if(Func.isNotEmpty(rescueNoticeDetailVO)){
			// 补充告警详情
			if(Func.isNotEmpty(rescueNoticeDetailVO.getPlanId())){
				// 工单状态描述补充
				Integer status = rescueNoticeDetailVO.getStatus();
				Integer typeStatus = rescueNoticeDetailVO.getTypeStatus();
				if(Func.isNotEmpty(status) && Func.isNotEmpty(typeStatus)){
					rescueNoticeDetailVO.setStatusDesc(TaskStatusEnum.getTaskName(typeStatus, status));
				}
			}
			String eventCode = rescueNoticeDetailVO.getEventCode();
			if(Func.isNotEmpty(eventCode)){
				rescueNoticeDetailVO.setEventCodeDesc(RescueNoticeTypeEnum.getSourceByEventCode(eventCode));
			}
			if(Func.isNotEmpty(rescueNoticeDetailVO.getIsStop())){
				if(Integer.valueOf(1).equals(rescueNoticeDetailVO.getIsStop())){
					rescueNoticeDetailVO.setIsStopDesc("正常");
				}else{
					rescueNoticeDetailVO.setIsStopDesc("停梯");
				}
			}
			// 电梯已知的情况,电梯维保组,电梯责任人
			Long elevatorId = rescueNoticeDetailVO.getElevatorId();
			if(Func.isNotEmpty(elevatorId)){
				String principalDeptNames = elevatorPrincipalDeptService.getPrincipalDeptNames(elevatorId);
				rescueNoticeDetailVO.setPrincipalDeptNames(principalDeptNames);
				String principalUserNames = elevatorPrincipalDeptService.getPrincipalUseNames(elevatorId);
				rescueNoticeDetailVO.setPrincipalUserNames(principalUserNames);
			}


			// 确认状态和类型
			if(!Integer.valueOf(-1).equals(rescueNoticeDetailVO.getConfirmType())){
				rescueNoticeDetailVO.setConfirmTypeDesc(RescueNoticeConfirmTypeEnum.getConfirmTypeDescByConfirmType(rescueNoticeDetailVO.getConfirmType()));
				rescueNoticeDetailVO.setConfirmStatusDesc(Boolean.TRUE);
			}else{
				rescueNoticeDetailVO.setConfirmStatusDesc(Boolean.FALSE);
			}
			// 物业联系人信息，业务上不可能存在当前告警id不存在，以及当前告警下的项目id不存在
			RescueNotice currentNotice = this.getById(rescueNoticeId);

			Long buildingId = currentNotice.getBuildingId();
			List<BuildingContacts> contacts = buildingContactsService.list(new LambdaQueryWrapper<BuildingContacts>()
				.eq(BuildingContacts::getBuildingId, buildingId)
				.eq(BaseEntity::getIsDeleted, 0)
			);
			if(Func.isNotEmpty(contacts)){
				List<String> linkMessage = new ArrayList<>(contacts.size());
				List<RescueEstateLinkmanVO> estateLinkman = new ArrayList<>(contacts.size());
				contacts.forEach(c -> {
					RescueEstateLinkmanVO rescueEstateLinkmanVO = new RescueEstateLinkmanVO();
					String contactsName = c.getContactsName();
					String phone = c.getPhone();
					rescueEstateLinkmanVO.setUserName(contactsName);
					rescueEstateLinkmanVO.setPhone(phone);
					linkMessage.add(
						(Func.isEmpty(contactsName) ? "" : contactsName)
								+ (Func.isEmpty(phone) ? "" : phone)
								+";");
					estateLinkman.add(rescueEstateLinkmanVO);
				});
				// 将linkMessage List<String> 转成String
				String linkMessageStr = String.join(",", linkMessage);
				rescueNoticeDetailVO.setEstateLinkMessage(linkMessageStr);
				rescueNoticeDetailVO.setEstateLinkman(estateLinkman);
			}
			// 微信群AI告警类型,会话相关
			if(Func.isNotEmpty(rescueNoticeDetailVO.getEventCode())){
				if(rescueNoticeDetailVO.getEventCode().equals(RescueNoticeTypeEnum.CHAT_GROUP_AI.getEventCode())){
					AIRescueNoticeVO aiRescueNoticeVO = new AIRescueNoticeVO();
					// 会话信息
					List<RescueNoticeAiSession> sessionList = aiNoticeSessionService.list(new LambdaQueryWrapper<RescueNoticeAiSession>()
						.eq(RescueNoticeAiSession::getNoticeId, rescueNoticeId)
						.eq(BaseEntity::getIsDeleted, 0)
					);
					// 会话内容
					if(Func.isNotEmpty(sessionList)){
						RescueNoticeAiSession rescueNoticeAiSession = sessionList.get(0);
						aiRescueNoticeVO.setRescueNoticeAiSession(rescueNoticeAiSession);
						Long sessionId = rescueNoticeAiSession.getId();
						List<RescueNoticeAiSessionContent> contentList = aiNoticeSessionContentService.list(new LambdaQueryWrapper<RescueNoticeAiSessionContent>()
							.eq(BaseEntity::getIsDeleted, 0)
							.eq(RescueNoticeAiSessionContent::getAiSessionId, sessionId)
						);
						aiRescueNoticeVO.setRescueNoticeAiSessionContents(contentList);
						rescueNoticeDetailVO.setAiRescueNoticeVO(aiRescueNoticeVO);
					}
				}
			}
		}
		return rescueNoticeDetailVO;
	}

	@Override
	public List<ExistRescuePlanVO> existRescueNoticeList(Long elevatorId) {
		List<ExistRescuePlanVO> existRescuePlanVOS = baseMapper.existRescueNoticeList(elevatorId);
		if(Func.isNotEmpty(existRescuePlanVOS)){
			existRescuePlanVOS.forEach(r -> r.setStatusDesc(TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_KR.getId(),r.getStatus())));
		}
		return existRescuePlanVOS;
	}
}
